package com.lonely.goods.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.core.domain.Tree;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.goods.domain.dto.material.group.GroupSubmitDTO;
import com.lonely.goods.domain.entity.SysMaterial;
import com.lonely.goods.domain.entity.SysMaterialTypeGroup;
import com.lonely.goods.domain.vo.material.group.MaterialTypeGroupVO;
import com.lonely.goods.mapper.SysMaterialTypeGroupMapper;
import com.lonely.goods.service.IMaterialService;
import com.lonely.goods.service.IMaterialTypeGroupService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/7/10 10:02
 * @description: 物料类型分组服务实现类
 */
@Service
public class MaterialTypeGroupServiceImpl extends ServiceImpl<SysMaterialTypeGroupMapper, SysMaterialTypeGroup> implements IMaterialTypeGroupService {

    @Autowired
    private IMaterialService materialService;

    /**
     * 获取物料类型分组树
     *
     * @return
     */
    @Override
    public Tree getTree() {
        List<SysMaterialTypeGroup> allTypes = super.list();

        List<Tree> groupTree = new ArrayList<>();
        if (CollUtil.isNotEmpty(allTypes)) {
            // 转换成树形结构
            groupTree.addAll(Optional.ofNullable(recursionGeneratorGroupTree(allTypes, 0L)).orElse(new ArrayList<>()));
        }

        // 添加默认全部组节点
        Tree rootTree = new Tree();
        rootTree.setKey("0");
        rootTree.setLabel("全部");
        rootTree.setChildren(groupTree);
        return rootTree;
    }

    /**
     * 递归构建分类树
     *
     * @param allGroups
     * @param parentGroupId
     * @return
     */
    private List<Tree> recursionGeneratorGroupTree(List<SysMaterialTypeGroup> allGroups, Long parentGroupId) {
        // 找到当前父级下的所有子级
        List<SysMaterialTypeGroup> groups = allGroups.stream().filter(currentGroup -> Objects.equals(currentGroup.getParentId(), parentGroupId)).collect(Collectors.toList());
        if (CollUtil.isEmpty(groups)) {
            return null;
        }

        List<Tree> tree = new ArrayList<>();
        for (SysMaterialTypeGroup currentGroup : groups) {
            Tree currentTree = new Tree();
            currentTree.setKey(StrUtil.toString(currentGroup.getId()));
            currentTree.setLabel(currentGroup.getTypeName());
            currentTree.setChildren(recursionGeneratorGroupTree(allGroups, currentGroup.getId()));
            tree.add(currentTree);
        }
        return tree;
    }


    /**
     * 创建组
     *
     * @param submitDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGroup(GroupSubmitDTO submitDTO) {
        Assert.isNull(submitDTO.getId(), "参数错误(id)");

        //1. 校验组信息
        this.checkGroupInfo(submitDTO);

        //2. 入库
        SysMaterialTypeGroup sysMaterialTypeGroup = new SysMaterialTypeGroup();
        sysMaterialTypeGroup.setParentId(submitDTO.getParentId());
        sysMaterialTypeGroup.setTypeName(submitDTO.getTypeName());
        sysMaterialTypeGroup.setCreateBy(SecurityUtils.getUserId());
        sysMaterialTypeGroup.setUpdateBy(SecurityUtils.getUserId());
        super.save(sysMaterialTypeGroup);

        // 3. 更新父子链关系
        if (submitDTO.getParentId() != 0L) {
            SysMaterialTypeGroup parentGroup = super.getById(submitDTO.getParentId());
            sysMaterialTypeGroup.setAncestors(String.format("%s,%s", parentGroup.getAncestors(), submitDTO.getId()));
        } else {
            sysMaterialTypeGroup.setAncestors("0");
        }
        super.updateById(sysMaterialTypeGroup);
    }

    /**
     * 编辑组
     *
     * @param submitDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editGroup(GroupSubmitDTO submitDTO) {
        Assert.notNull(submitDTO.getId(), "参数错误(id)");

        //1. 校验组信息
        this.checkGroupInfo(submitDTO);

        //2. 入库
        SysMaterialTypeGroup oldGroup = super.getById(submitDTO.getId());
        Assert.notNull(oldGroup, "分组不存在");
        oldGroup.setParentId(submitDTO.getParentId());
        oldGroup.setTypeName(submitDTO.getTypeName());
        oldGroup.setUpdateBy(SecurityUtils.getUserId());

        if (submitDTO.getParentId() != 0L) {
            SysMaterialTypeGroup parentGroup = super.getById(submitDTO.getParentId());
            oldGroup.setAncestors(String.format("%s,%s", parentGroup.getAncestors(), submitDTO.getId()));
        } else {
            oldGroup.setAncestors("0");
        }
        super.updateById(oldGroup);
    }

    /**
     * 删除指定组
     *
     * @param groupId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGroup(Long groupId) {
        SysMaterialTypeGroup group = super.getById(groupId);
        Assert.notNull(group, "分组不存在");

        // 校验该分组下是否存在子分组
        int count = super.count(new LambdaQueryWrapper<SysMaterialTypeGroup>().eq(SysMaterialTypeGroup::getParentId, groupId));
        Assert.isTrue(count == 0, "该分组下存在子分组，请先删除子分组");

        // 判断该分组是否被物料引用了
        int groupReferenceCount = this.materialService.count(new LambdaQueryWrapper<SysMaterial>().eq(SysMaterial::getType, groupId));
        Assert.isTrue(groupReferenceCount == 0, "该分组被物料引用，请先解除引用");

        // 执行删除
        super.removeById(groupId);
    }

    /**
     * 获取指定组信息
     *
     * @param groupId
     * @return
     */
    @Override
    public MaterialTypeGroupVO getById(Long groupId) {
        SysMaterialTypeGroup materialTypeGroup = super.getById(groupId);
        Assert.notNull(materialTypeGroup, "物料类型不存在");

        MaterialTypeGroupVO materialTypeGroupVO = new MaterialTypeGroupVO();
        BeanUtils.copyProperties(materialTypeGroup, materialTypeGroupVO);
        return materialTypeGroupVO;
    }

    /**
     * 校验组信息
     *
     * @param submitDTO
     */
    private void checkGroupInfo(GroupSubmitDTO submitDTO) {
        //1. 验证当前组下不能存在相同的名称
        int count = super.count(new LambdaQueryWrapper<SysMaterialTypeGroup>()
                .eq(SysMaterialTypeGroup::getParentId, submitDTO.getParentId())
                .eq(SysMaterialTypeGroup::getTypeName, submitDTO.getTypeName())
                .ne(submitDTO.getId() != null, SysMaterialTypeGroup::getId, submitDTO.getId())
        );
        Assert.isTrue(count == 0, "该分组下已存在该名称的分组");

        //2. 验证父id的有效性
        if (submitDTO.getParentId() != 0L) {
            SysMaterialTypeGroup parentGroup = super.getById(submitDTO.getParentId());
            Assert.notNull(parentGroup, "父级分组不存在");
        }
    }
}
